package org.goatsoft.catchpeaks;

import java.text.MessageFormat;
import java.util.Collections;
import java.util.List;
import java.util.Stack;

import org.goatsoft.catchpeaks.player.FirstMatchPlayer;

public class CatchPeaks {

	/*
	 *          [00]              [01]              [02]
	 *       [03]  [04]        [05]  [06]        [07]  [08]
	 *    [09]  [10]  [11]  [12]  [13]  [14]  [15]  [16]  [17]
	 * [18]  [19]  [20]  [21]  [22]  [23]  [24]  [25]  [26]  [27]
	 * 
	 * 
	 *                                 [28]
	 */

	public static final Card FACE_DOWN_CARD = new Card(null, null);

	private static enum GameState { GAME_IN_PROGRESS, GAME_FINISHED_WIN, GAME_FINISHED_LOSE, GAME_FINISHED_GIVE_UP }

	public GameState play() {
		Stack<Card> deck = createShuffledDeck();
		Card[] state = createInitialState(deck);
		Player player = createPlayer();
		GameState gameState = GameState.GAME_IN_PROGRESS;
		while (gameState == GameState.GAME_IN_PROGRESS) {
			Card[] stateWithFaceDown = createStateWithFaceDown(state);
			displayState(stateWithFaceDown);
			int move = player.move(stateWithFaceDown);
			boolean isValidMove = Util.isValidMove(state, move);
			if (isValidMove) {
				gameState = performMove(state, move, deck);
			} else {
				throw new IllegalArgumentException("Fuck off!");
			}
		}
		displayResult(gameState);
		return gameState;
	}

	public int playTournament(int times) {
		int result = 0;
		for (int i = 0; i < times; i++) {
			GameState gameResult = play();
			if (gameResult == GameState.GAME_FINISHED_WIN) {
				result++;
			}
		}
		return result;
	}

	private Card[] createInitialState(Stack<Card> deck) {
		Card[] state = new Card[29];
		for (int i = 0; i < state.length; i++) {
			state[i] = deck.pop();
		}
		return state;
	}

	private Stack<Card> createShuffledDeck() {
		List<Card> deckList = Deck.createDeck();
		Collections.shuffle(deckList);
		Stack<Card> deck = new Stack<Card>();
		for (Card card : deckList) {
			deck.push(card);
		}
		return deck;
	}

	private Player createPlayer() {
		return new DPlayer();
	}

	private Card[] createStateWithFaceDown(Card[] state) {
		Card[] result = new Card[state.length];
		for (int i = 0; i < result.length; i++) {
			if (Util.isFaceDown(state, i)) {
				result[i] = FACE_DOWN_CARD;
			} else {
				result[i] = state[i];
			}
		}
		return result;
	}

	private void displayState(Card[] stateWithFaceDown) {
		String template = "          [{0}]              [{1}]              [{2}]\r\n" +
				"       [{3}]  [{4}]        [{5}]  [{6}]        [{7}]  [{8}]\r\n" +
				"    [{9}]  [{10}]  [{11}]  [{12}]  [{13}]  [{14}]  [{15}]  [{16}]  [{17}]\r\n" +
				" [{18}]  [{19}]  [{20}]  [{21}]  [{22}]  [{23}]  [{24}]  [{25}]  [{26}]  [{27}]\r\n" +
				" \r\n" +
				" \r\n" +
				"                                 [{28}]\r\n";
		String[] arguments = new String[stateWithFaceDown.length];
		for (int i = 0; i < stateWithFaceDown.length; i++) {
			String argument;
			if (stateWithFaceDown[i] == FACE_DOWN_CARD) {
				argument = " ?";
			} else if (stateWithFaceDown[i] == null) {
				argument = "  ";
			} else {
				argument = stateWithFaceDown[i].getValue().toString();
				if (argument.startsWith("_")) {
					argument = argument.substring(1);
				}
				if (argument.length() == 1) {
					argument = " " + argument;
				}
			}
			arguments[i] = argument;
		}
		System.out.println(MessageFormat.format(template, (Object[]) arguments));
	}

	private void displayResult(GameState gameState) {
		System.out.println(gameState);
	}

	private GameState performMove(Card[] state, int move, Stack<Card> deck) {
		GameState result = GameState.GAME_IN_PROGRESS;
		if (move == -1) {
			result = GameState.GAME_FINISHED_GIVE_UP;
		} else if (move < state.length - 1) {
			state[state.length - 1] = state[move];
			state[move] = null;

			boolean isWin = true;
			for (int i = 0; i < state.length - 1; i++) {
				if (state[i] != null) {
					isWin = false;
					break;
				}
			}
			if (isWin) {
				result = GameState.GAME_FINISHED_WIN;
			}
		} else {
			if (deck.isEmpty()) {
				result = GameState.GAME_FINISHED_LOSE;
			} else {
				state[state.length - 1] = deck.pop();
			}
		}
		return result;
	}

	public static void main(String[] args) {
		//		new CatchPeaks().play();
		int tournamentSize = 1000;
		int result = new CatchPeaks().playTournament(tournamentSize);
		System.out.println("Won " + ((result * 100) / tournamentSize) + "%.");

	}
}
